package com.hc.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;

/**
 * springsecurity核心配置
 *
 * @author 梁云亮
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Resource
    private LoginFailureHandler loginFailureHandler;
    @Resource
    private LoginSuccessHandler loginSuccessHandler;
    @Resource
    private VerifyCodeFilter verifyCodeFilter;
    @Resource
    private MyAuthenticationEntryPoint myAuthenticationEntryPoint;
    @Resource
    private TokenAccessDeniedHandler tokenAccessDeniedHandler;
    @Resource
    private MyLogoutSuccessHandler myLogoutSuccessHandler; //注销处理器

    @Bean
    public TokenAuthenticationFilter tokenAuthenticationFilter() throws Exception {
        TokenAuthenticationFilter tokenAuthenticationFilter = new TokenAuthenticationFilter(authenticationManager());
        return tokenAuthenticationFilter;
    }

    //白名单
    private static final String[] whiteUrl = {
            "/login", "/logout", "/user/v1/getVerifyCode"
    };

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors()
                .and()
                .csrf().disable()  //跨域攻击防护
                //登录配置
                .formLogin()
                .successHandler(loginSuccessHandler)
                .failureHandler(loginFailureHandler)
                .loginProcessingUrl("/login")  //默认
                .usernameParameter("username") //默认
                .passwordParameter("password") //默认

                .and() //配置退出
                .logout()
                .logoutUrl("/logout") //默认
                .logoutSuccessHandler(myLogoutSuccessHandler)//注销时的逻辑处理

                .and()         //禁用Session、cookie
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)

                .and()  //配置拦截规则
                .authorizeRequests().antMatchers(whiteUrl).permitAll() //白名单
                .anyRequest().authenticated() //所有请求都需要认证后才能访问

                .and() //认证失败，异常处理器
                .exceptionHandling()
                .authenticationEntryPoint(myAuthenticationEntryPoint) //未登录时的处理逻辑
                .accessDeniedHandler(tokenAccessDeniedHandler) //权限不足时的处理逻辑

                .and()      //配置自定义过滤器
                .addFilter(tokenAuthenticationFilter()) //自动登录
                .addFilterBefore(verifyCodeFilter, UsernamePasswordAuthenticationFilter.class) //系统默认
        ;
    }

    //加密
    @Bean
    public PasswordEncoder passwordEncoder() { //创建加密对象：使用系统自带的加密自算法
        return new BCryptPasswordEncoder();
    }

    @Resource
    private MyUserDetailService myUserDetailService;

    //认证 -- 登录
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailService)
                .passwordEncoder(passwordEncoder())
                //.and() //在内存中配置用户名和密码(可以在测试时使用)
                //.inMemoryAuthentication().withUser("hc").password(passwordEncoder().encode("hc")).roles("admin")
                ; //配置加密算法，这一行代码可以省略
    }
}






